package com.llc.gulimall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.llc.common.constant.OrderConstant;
import com.llc.common.exception.BizCodeEnume;
//import com.llc.common.exception.BizException;
import com.llc.common.exception.BizException;
import com.llc.common.to.mq.OrderTo;
import com.llc.common.to.mq.SeckillOrderTo;
import com.llc.common.utils.R;
import com.llc.common.vo.MemberResponseVo;
import com.llc.gulimall.order.dao.OrderItemDao;
import com.llc.gulimall.order.entity.OrderItemEntity;
import com.llc.gulimall.order.feign.CartFeignService;
import com.llc.gulimall.order.feign.MemberFeignService;
import com.llc.gulimall.order.feign.ProductFeignService;
import com.llc.gulimall.order.feign.WareFeignService;
import com.llc.gulimall.order.interceptor.LoginUserInterceptor;
import com.llc.gulimall.order.service.OrderItemService;
import com.llc.gulimall.order.to.OrderCreateTo;
import com.llc.gulimall.order.vo.*;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.llc.common.utils.PageUtils;
import com.llc.common.utils.Query;

import com.llc.gulimall.order.dao.OrderDao;
import com.llc.gulimall.order.entity.OrderEntity;
import com.llc.gulimall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    OrderDao orderDao;

    @Autowired
    OrderItemService orderItemService;

    @Autowired
    MemberFeignService memberFeignService;

    @Autowired
    CartFeignService cartFeignService;

    @Autowired
    ThreadPoolExecutor executor;

    @Autowired
    WareFeignService wareFeignService;

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    RabbitTemplate rabbitTemplate;

    private ThreadLocal<OrderSubmitVo> confirmVoThreadLocal = new ThreadLocal<>();

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo confirmVo = new OrderConfirmVo();
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
        //同步ok
        //List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
        //confirmVo.setAddresses(address);
        //List<OrderItemVo> items = cartFeignService.getCurrentCartItems();
        //confirmVo.setItems(items);

        /**
         * 解决异步失真
         */
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();


        CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
            //1 远程查询所有收货地址列表
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
            System.out.println("address:" + address);
            confirmVo.setAddresses(address);
        }, executor);

        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            //2 远程查询所有购物车中选中的购物项
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> items = cartFeignService.getCurrentCartItems();
            System.out.println("items:" + items);
            confirmVo.setItems(items);
        }, executor).thenRunAsync(() -> {
            List<OrderItemVo> items = confirmVo.getItems();
            List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
            R hasStock = wareFeignService.getSkuHasStock(collect);
            List<SkuStockVo> data = (List<SkuStockVo>) hasStock.getData(new TypeReference<List<SkuStockVo>>() {
            });
            if (data != null) {
                Map<Long, Boolean> map = data.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock));
                confirmVo.setStocks(map);
                System.out.println("map" + map);
            }

        }, executor);
        CompletableFuture.allOf(getAddressFuture, cartFuture).get();
        System.out.println("执行成功");
        //3 查询用户积分
        Integer integration = memberResponseVo.getIntegration();
        confirmVo.setIntegration(integration);

        //4 其他数据计算

        // 5 防重令牌
        String token = UUID.randomUUID().toString().replace("-", "");
        //给服务器设置
        redisTemplate.opsForValue().set(OrderConstant.ORDER_TOKEN_PREFIX + memberResponseVo.getId(), token, 30, TimeUnit.MINUTES);
        //给页面设置令牌
        confirmVo.setOrderToken(token);
        ;
        return confirmVo;
    }


    /**
     * 下单实现
     */
    //@GlobalTransactional
    @Transactional
    @Override
    public SubmitOrderResponseVo submitOrder(OrderSubmitVo submitVo) {

        confirmVoThreadLocal.set(submitVo);
        SubmitOrderResponseVo response = new SubmitOrderResponseVo();
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
        String orderToken = submitVo.getOrderToken();
        response.setCode(0);
        // TODO 1.验证令牌
        String key = OrderConstant.ORDER_TOKEN_PREFIX + memberResponseVo.getId();
        //获取令牌、验证令牌、删除令牌 应该是原子性操作  0 失败 1 成功
        String redisToken = redisTemplate.opsForValue().get(key);

        //if (StringUtils.equals(orderToken, redisToken)) {
        //    // 验证通过，删除令牌
        //    redisTemplate.delete(OrderConstant.ORDER_TOKEN_PREFIX + memberResponseVo.getId());
        //}
        //else {
        //    //log.warn("订单令牌校验失败，已创建或已过期，请重新下单");
        //    //throw new BizException(BizCodeEnume.ORDER_HAS_EXPIRED);
        //}
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        Long res = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(key), orderToken);
        if (res == 0L) {
            response.setCode(1);
            log.warn("订单令牌校验失败，已创建或已过期，请重新下单");
            throw new BizException(BizCodeEnume.ORDER_HAS_EXPIRED);
        } else {
            //1 创建订单
            OrderCreateTo order = createOrder();
            //2 验价
            BigDecimal payAmount = order.getOrder().getPayAmount();
            BigDecimal payPrice = submitVo.getPayPrice();
            if(Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.01){
                //对比成功
                //3 保存到数据库
                System.out.println("能到这，保存之前");
                saveOrder(order);
                // 4 库存锁定 有异常就回滚 订单号 订单项（skuid num  skuname）
                WareSkuLockVo lockVo = new WareSkuLockVo();
                lockVo.setOrderSn(order.getOrder().getOrderSn());
                List<OrderItemVo> locks = order.getOrderItems().stream().map(item -> {
                    OrderItemVo itemVo = new OrderItemVo();
                    itemVo.setSkuId(item.getSkuId());
                    itemVo.setCount(item.getSkuQuantity());
                    itemVo.setTitle(item.getSkuName());
                    return itemVo;
                }).collect(Collectors.toList());
                lockVo.setLocks(locks);
                //TODO 远程库存
                R r = wareFeignService.orderLockStock(lockVo);
                if(r.getCode() == 0){
                    //库存锁定成功
                    response.setOrder(order.getOrder());
                    rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder());
                    System.out.println("order 送成功");
                    //int i = 10/0;
                    System.out.println("锁定成功");
                    return response;
                }else {
                    //锁定失败
                    response.setCode(3);
                    return response;
                }
            } else{
                response.setCode(2);
                return response;
            }
        }
    }

    /**
     *
     * @author llc
     * @description  关闭订单
     * @date 2022/2/17 23:22
     * @param entity
     * @return void
     */

    @Override
    public void closeOrder(OrderEntity entity) {
        //查询当前订单的状态
        OrderEntity orderEntity = this.getById(entity.getId());
        if(orderEntity.getStatus() == OrderConstant.OrderStatusEnum.CREATE_NEW.getCode()){
            //关闭订单
            OrderEntity update = new OrderEntity();
            update.setId(entity.getId());
            update.setStatus(OrderConstant.OrderStatusEnum.CANCLED.getCode());
            this.updateById(update);
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderEntity,orderTo);
            // 发给MQ一个
            System.out.println("发送订单关闭的MQ");
            //序列化报错 导致发不出去
            rabbitTemplate.convertAndSend("order-event-exchange","order.release.other",orderTo);
            System.out.println("给ware发送成功");
        }
    }


    /**
     *
     * @author llc
     * @description  创建秒杀订单
     * @date 2022/2/21 1:52
     * @param seckillOrder
     * @return void
     */

    @Override
    public void createSeckillOrder(SeckillOrderTo seckillOrder) {
        // TODO 保存订单信息
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(seckillOrder.getOrderSn());
        orderEntity.setMemberId(seckillOrder.getMemberId());
        orderEntity.setStatus(OrderConstant.OrderStatusEnum.CREATE_NEW.getCode());
        BigDecimal totalPrice = seckillOrder.getSeckillPrice().multiply(new BigDecimal(seckillOrder.getNum()));
        orderEntity.setPayAmount(totalPrice);
        this.save(orderEntity);

        //TODO 获取sku详细信息
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        orderItemEntity.setOrderSn(seckillOrder.getOrderSn());
        orderItemEntity.setRealAmount(totalPrice);

        orderItemEntity.setSkuQuantity(seckillOrder.getNum());
        orderItemService.save(orderItemEntity);
    }
    /**
     *
     * @author llc
     * @description  获取订单的支付信息
     * @date 2022/3/1 20:06
     * @param orderSn
     * @return com.llc.gulimall.order.vo.PayVo
     */

    @Override
    public PayVo getOrderPay(String orderSn) {
        PayVo payVo = new PayVo();

        OrderEntity order = this.getOrderByOrderSn(orderSn);

        List<OrderItemEntity> order_sn = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
        OrderItemEntity entity = order_sn.get(0);
        BigDecimal bigDecimal = order.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
        payVo.setTotal_amount(bigDecimal.toString());
        payVo.setOut_trade_no(order.getOrderSn());
        //设置商品名
        payVo.setBody(entity.getSkuAttrsVals());
        payVo.setSubject(entity.getSkuName());
        return payVo;
    }
    /**
     *
     * @author llc
     * @description  用于查询相关信息
     * @date 2022/3/2 0:48
     * @param params
     * @return com.llc.common.utils.PageUtils
     */

    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id",memberResponseVo.getId()).orderByDesc("id"));
        List<OrderEntity> order_sn = page.getRecords().stream().map(order -> {
            List<OrderItemEntity> itemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", order.getOrderSn()));
            order.setItemEntities(itemEntities);
            return order;
        }).collect(Collectors.toList());
        page.setRecords(order_sn);
        return new PageUtils(page);
    }


    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        OrderEntity order_sn = this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", orderSn));
        return order_sn;
    }

    /**
     * 保存订单所有数据
     * @param order
     */

    private void saveOrder(OrderCreateTo order) {
        OrderEntity orderEntity = order.getOrder();
        orderEntity.setModifyTime(new Date());
        this.save(orderEntity);
        List<OrderItemEntity> orderItems = order.getOrderItems();
        System.out.println("保存成功");
        System.out.println("orderItems:"+orderItems);
        orderItemService.saveBatch(orderItems);


    }


    private OrderCreateTo createOrder(){
        OrderCreateTo createTo = new OrderCreateTo();
        //1 生成订单号
        String orderSn = IdWorker.getTimeId();
        //创建订单
        OrderEntity orderEntity = buildOrder(orderSn);
        // 2 获取所有订单项
        List<OrderItemEntity> itemEntities = builderOrderItems(orderSn);

        // 3 验价
        computePrice(orderEntity,itemEntities);

        //保存数据
        createTo.setOrder(orderEntity);
        createTo.setOrderItems(itemEntities);
        // 收货日期
        ////订单项
        //List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
        //if(currentCartItems != null && currentCartItems.size() > 0){
        //    currentCartItems.stream().map(cartItem ->{
        //        OrderItemEntity itemEntity = bulidOrderItem(cartItem);;
        //        bulidOrderItem(cartItem);
        //        return itemEntity;
        //
        //    }).collect(Collectors.toList());
        //}

        // 3.支付信息
        //entity.setPayType(submitVO.getPayType());
        return createTo;

    }

    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> itemEntities) {
        int growth = 0,integration = 0;
        BigDecimal couponAmount = new BigDecimal("0");
        BigDecimal promotionAmount = new BigDecimal("0");
        BigDecimal integrationAmount = new BigDecimal("0");
        BigDecimal total = new BigDecimal(0.0);
        // 价格相关  订单项总计添加
        for(OrderItemEntity entity: itemEntities){
            BigDecimal realAmount = entity.getRealAmount();
            couponAmount = couponAmount.add(entity.getCouponAmount());
            promotionAmount = promotionAmount.add(entity.getPromotionAmount());
            integrationAmount =integrationAmount.add(entity.getIntegrationAmount());
            total = total.add(realAmount);
            growth = growth + entity.getGiftGrowth();
            integration = integration + entity.getGiftIntegration();
        }
        orderEntity.setTotalAmount(total);
        orderEntity.setCouponAmount(couponAmount);
        orderEntity.setPromotionAmount(promotionAmount);
        orderEntity.setIntegrationAmount(integrationAmount);
        //加上运费
        orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));
        //设置成长积分
        orderEntity.setGrowth(growth);
        orderEntity.setIntegration(integration);
        orderEntity.setDeleteStatus(0); //未删除
    }

    private OrderEntity buildOrder(String orderSn) {
        MemberResponseVo responseVo = LoginUserInterceptor.loginUser.get();
        OrderEntity entity = new OrderEntity();
        entity.setOrderSn(orderSn);
        entity.setMemberId(responseVo.getId());
        //获取收获地址
        OrderSubmitVo submitVo = confirmVoThreadLocal.get();
        R fare = wareFeignService.getFare(submitVo.getAddrId());
        FareVo fareResp = (FareVo) fare.getData(new TypeReference<FareVo>() {
        });
        //设置运费
        entity.setFreightAmount(fareResp.getFare());
        // 城市等
        entity.setReceiverCity(fareResp.getAddress().getCity());
        entity.setReceiverDetailAddress(fareResp.getAddress().getDetailAddress());
        entity.setReceiverName(fareResp.getAddress().getName());
        entity.setReceiverPhone(fareResp.getAddress().getPhone());
        entity.setReceiverProvince(fareResp.getAddress().getProvince());

        //订单状态
        entity.setStatus(OrderConstant.OrderStatusEnum.CREATE_NEW.getCode());

        //设置过期时间
        entity.setAutoConfirmDay(7);
        return entity;
    }


    /**
     * 构建所有订单项
     * @return
     */
    private List<OrderItemEntity> builderOrderItems(String orderSn){
        //最后确定每个价格
        List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
        if(currentCartItems != null && currentCartItems.size() > 0){
            List<OrderItemEntity> itemEntities = currentCartItems.stream().map(cartItem -> {
                OrderItemEntity itemEntity = buildOrderItem(cartItem);
                itemEntity.setOrderSn(orderSn);
                //buildOrderItem(cartItem);
                return itemEntity;
            }).collect(Collectors.toList());
            return itemEntities;
        }
        return null;
    }

    /**
     * 构建每一个订单项
     * @param cartItem
     * @return
     */
    private OrderItemEntity buildOrderItem(OrderItemVo cartItem){
        OrderItemEntity itemEntity = new OrderItemEntity();
        // 1. sku部分
        itemEntity.setSkuId(cartItem.getSkuId());
        itemEntity.setSkuName(cartItem.getTitle());
        itemEntity.setSkuPrice(cartItem.getPrice());
        itemEntity.setSkuPic(cartItem.getImage());
        itemEntity.setSkuQuantity(cartItem.getCount());
        //itemEntity.setSkuAttrsVals(cartItem.getSkuAttrValues().stream().collect(Collectors.joining(";")));
        itemEntity.setSkuAttrsVals("红色");
        //订单信息

        // 2. spu部分
        R r = productFeignService.getSpuInfoBySku(cartItem.getSkuId());
        if (r.getCode() != 0) {
            log.error("gulimall-order调用gulimall-product查询spuinfo失败");
            //throw new BizException(BizCodeEnume.CALL_FEIGN_SERVICE_FAILED, "下单失败请重新");

        }
        System.out.println("到达这");
        SpuInfoVo data = (SpuInfoVo) r.getData(new TypeReference<SpuInfoVo>() {
        });
        System.out.println("到这失败");
        itemEntity.setSpuId(data.getId());
        itemEntity.setSpuName(data.getSpuName());
        // orderItemVO.setSpuPic;
        itemEntity.setSpuBrand(data.getBrandId().toString());
        itemEntity.setCategoryId(data.getCatalogId());

        // 3.积分部分
        itemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())).intValue());
        itemEntity.setGiftIntegration(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())).intValue());

        //订单项价格信息
        itemEntity.setPromotionAmount(new BigDecimal(0));
        itemEntity.setCouponAmount(new BigDecimal(0));
        itemEntity.setIntegrationAmount(new BigDecimal(0));
        //实际金额
        BigDecimal orgin = itemEntity.getSkuPrice().multiply(new BigDecimal(itemEntity.getSkuQuantity().toString()));
        //总额减去各种优惠
        BigDecimal price = orgin.subtract(itemEntity.getPromotionAmount()).subtract(itemEntity.getCouponAmount()).subtract(itemEntity.getIntegrationAmount());
        itemEntity.setRealAmount(price);
        return itemEntity;
    }

}